//! fql 文件解析器

use std::{collections::HashMap, fmt::Display, fs::File};
use std::{io::prelude::*, ops::Deref};
use std::{io::BufReader, ops::DerefMut};

use crate::ForceUnwrap;
use serde_json::json;

/// FQL支持 的数据类型
#[derive(Clone, Debug, PartialEq, PartialOrd)]
pub enum FQLType {
    /// 字符串
    String(String),
    /// 浮点数
    Float(f64),
    /// 整型
    Int(i64),
    /// 未定义
    Null,
}

impl Into<serde_json::Value> for FQLType {
    fn into(self) -> serde_json::Value {
        match self {
            Self::String(s) => json!(s),
            Self::Int(s) => json!(s),
            Self::Float(s) => json!(s),
            Self::Null => serde_json::Value::Null,
        }
    }
}

impl std::fmt::Display for FQLType {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            Self::String(s) => write!(f, "\"{}\"", s),
            Self::Int(s) => write!(f, "{}", s),
            Self::Float(s) => write!(f, "{}", s),
            Self::Null => write!(f, "null"),
        }
    }
}

macro_rules! _impl_from_for_fqltype {

    (int: $($t:ty),*) => {
        $(
            impl From<$t> for FQLType {
                fn from(value: $t) -> Self {
                    Self::Int(value as i64)
                }
            }
        )*
    };
    (float: $($t:ty),*) => {
        $(
            impl From<$t> for FQLType {
                fn from(value: $t) -> Self {
                    Self::Float(value as f64)
                }
            }
        )*
    };
    (display: $($t:ty),*) => {
        $(
            impl From<$t> for FQLType {
                fn from(value: $t) -> Self {

                    if format!("{}", value) == "null" {
                        return Self::Null;
                    }

                    if let Ok(v) = value.parse::<i64>() {
                        return Self::Int(v);
                    }

                    if let Ok(v) = value.parse::<f64>() {
                        return Self::Float(v);
                    }

                    if value.starts_with("\"") && value.ends_with("\"") {
                        return Self::String(value[1..value.len() - 1].to_string());
                    }

                    Self::String(value.to_string())
                }
            }
        )*
    };
}

_impl_from_for_fqltype!(float: f32, f64);
_impl_from_for_fqltype!(display: String, &str, &String);
_impl_from_for_fqltype!(int: i8, u8, i16, u16, i32, u32, i64, u64, isize, usize);
/// 定义的每组数据
/// 代表一行的所有数据
#[derive(Clone, Debug)]
pub struct AppData(HashMap<String, FQLType>);

impl AppData {
    /// 更新数据
    pub fn update(&mut self, key: String, val: FQLType) {
        self.0.insert(key, val);
    }

    /// 获取内部数据
    pub fn inner(self) -> HashMap<String, FQLType> {
        self.0
    }

    /// 直接生成可序列化数据
    pub fn serialize(&self) -> HashMap<String, serde_json::Value> {
        let mut map = HashMap::new();
        for (k, v) in &self.0 {
            map.insert(k.to_string(), v.clone().into());
        }
        map
    }
}

impl From<HashMap<String, FQLType>> for AppData {
    fn from(data: HashMap<String, FQLType>) -> Self {
        AppData(data)
    }
}

impl AsRef<HashMap<String, FQLType>> for AppData {
    fn as_ref(&self) -> &HashMap<String, FQLType> {
        &self.0
    }
}

impl Deref for AppData {
    type Target = HashMap<String, FQLType>;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for AppData {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

/// 主控制器
/// # Examples
/// ```rust
/// use file_sql::*;
/// let app = App::from_file("example.fql");
/// ```
#[derive(Clone, Debug)]
pub struct App {
    /// 文件路径
    pub path: Option<String>,
    /// 储存数据
    pub data: Vec<AppData>,
    /// 键名列表
    pub keys: Vec<String>,
    /// 分隔符
    delimiter: String,
}

impl From<Vec<String>> for App {
    fn from(lines: Vec<String>) -> Self {
        let mut index = 0;
        let mut data = Vec::new();
        let delimiter = lines[0].trim().to_string();
        let keys: Vec<String> = lines[1].split(&delimiter).map(|s| s.to_string()).collect();

        for line in &lines[2..] {
            let mut map = HashMap::new();
            line.split(&delimiter)
                .enumerate()
                .into_iter()
                .for_each(|(i, s)| {
                    map.insert(keys[i].clone(), FQLType::from(s));
                    map.insert("$index".to_string(), FQLType::from(index));
                });
            data.push(AppData::from(map));
            index += 1;
        }

        Self {
            path: None,
            data,
            keys,
            delimiter,
        }
    }
}

impl From<&str> for App {
    fn from(s: &str) -> Self {
        App::from(
            s.split("\n")
                .map(|s| s.trim().to_string())
                .filter(|s| s.len() > 0)
                .collect::<Vec<String>>(),
        )
    }
}

impl From<Vec<AppData>> for App {
    fn from(data: Vec<AppData>) -> Self {
        if data.len() == 0 {
            return Self {
                path: None,
                data: Vec::new(),
                keys: Vec::new(),
                delimiter: "".to_string(),
            };
        }
        let keys: Vec<String> = data[0].keys().map(|s| s.to_string()).collect();
        Self {
            path: None,
            data,
            keys,
            delimiter: "".to_string(),
        }
    }
}

impl From<Vec<&AppData>> for App {
    fn from(data: Vec<&AppData>) -> Self {
        if data.len() == 0 {
            return Self {
                path: None,
                data: Vec::new(),
                keys: Vec::new(),
                delimiter: "".to_string(),
            };
        }
        let keys: Vec<String> = data[0].keys().map(|s| s.to_string()).collect();
        let data = data.into_iter().map(|s| s.clone()).collect();
        Self {
            path: None,
            data,
            keys,
            delimiter: "".to_string(),
        }
    }
}

impl Into<Vec<Vec<FQLType>>> for App {
    fn into(self) -> Vec<Vec<FQLType>> {
        self.data
            .into_iter()
            .map(|item| {
                item.values()
                    .map(|t| t.to_owned())
                    .collect::<Vec<FQLType>>()
            })
            .collect()
    }
}

impl App {
    /// 加载 fql 文件
    pub fn from_file<T: Display>(path: T) -> std::io::Result<Self> {
        File::open(format!("{}", path)).and_then(|f| {
            Ok(Self {
                path: Some(format!("{}", path)),
                ..Self::from(
                    BufReader::new(f)
                        .lines()
                        .map(|line| line.force_unwrap().trim().to_string())
                        .collect::<Vec<String>>(),
                )
            })
        })
    }

    /// 直接生成可序列化数据
    pub fn serialize(&self) -> Vec<HashMap<String, serde_json::Value>> {
        self.data.iter().map(|s| s.clone().serialize()).collect()
    }

    pub fn merge_data(&mut self, data: Vec<AppData>) {
        self.data = data;
    }

    /// 保存文件到指定位置
    pub fn save_at<T: Display>(&self, path: T) {
        let mut file = File::create(format!("{}", path)).unwrap();

        let head = format!("{}\n{}\n", self.delimiter, self.keys.join(&self.delimiter));

        file.write(head.as_bytes()).expect(&format!(
            "Parse::save_file failed at {} \ncontent: {}",
            path, head
        ));

        for data in &self.data {
            let line = self
                .keys
                .iter()
                .map(|s| format!("{}", data.get(s).force_unwrap()))
                .collect::<Vec<String>>()
                .join(&self.delimiter);
            file.write(line.as_bytes()).expect(&format!(
                "Parse::save_file failed at {} \ncontent: {}",
                path, line
            ));
            file.write(b"\n").force_unwrap();
        }
    }

    /// 创建空的数据
    pub fn create_data(&self) -> AppData {
        let mut map = HashMap::new();
        for key in &self.keys {
            map.insert(key.to_string(), FQLType::Null);
        }

        AppData::from(map)
    }

    /// 将指定数据初始化
    pub fn init_data(&self, data: &mut AppData) {
        data.0.clear();
        for key in &self.keys {
            data.0.insert(key.to_string(), FQLType::Null);
        }
    }

    /// 保存文件
    pub fn save(&self) {
        if let Some(path) = &self.path {
            self.save_at(&path);
        }
    }
}

#[cfg(test)]
mod test {
    use crate::*;
    use app::App;

    #[test]
    fn test_app_from_file() {
        let app = App::from_file("E:/web/rust-web/fql_server/uestc/student-info.csv".to_string())
            .unwrap();
        println!("{:#?}", app);

        //app.save_at("examples/save.fql");
    }

    #[test]
    fn test_app_from() {
        let mut app = App::from(
            r"
            ,
            year,month,day
            2020,12,14
            2019,05,12
            2018,10,null
            ",
        );
        app.update(0, "day", FQLType::Int(15));
        app.save_at("examples/save.fql");
        println!("{:#?}", app);
    }
}
